﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using IEx.Common;
using IEx.Model.Partials;
using IEx.Utilities;

namespace IEx.ParserBuilder.Otofun
{
    public class OtofunParser : IHtmlParser
    {
        public void Parse(SourceItem item, string html, Action<Model.Partials.Announcement> attachResultItem, Action<SourceItem> attachNewItemSource)
        {
            try
            {
                string firstThreadTitle = "threadtitle";
                string lastThreadTitle = "forum_info_options";
                string remainHtml = Utility.GetHtmlBody(html, firstThreadTitle, lastThreadTitle);
                List<Announcement> detectedAnnouncements = new List<Announcement>();                
                Uri newUri = Utility.CreateNewUriForNextPage(item.Url);

                if (!string.IsNullOrEmpty(remainHtml))
                {
                    Regex regexLiTags = new Regex("<li class=\"threadbit .*?\" id=\".*?\">.*?</li>");
                    MatchCollection mColLiTags = regexLiTags.Matches(remainHtml);

                    for (int i = 0; i < mColLiTags.Count; i++)
                    {
                        string threadTitle = string.Empty;
                        string threadLinkDetail = string.Empty;                        
                        string userName = string.Empty;
                        string userLinkDetail = string.Empty;
                        string postContent = string.Empty;
                        string dateTime = string.Empty;
                        DateTime postDate = DateTime.MinValue;

                        string threadContent = mColLiTags[i].Value.Trim();
                        threadContent = string.Join(string.Empty, Regex.Split(threadContent, @"(?:\r\n|\n|\r|\t)"));
                        //Extract Title topic here.
                        Regex regexThreadTitle = new Regex("<a class=\"title\" [^>]*>(.*?)</a>");
                        Match mThreadTitle = regexThreadTitle.Match(threadContent);
                        if (mThreadTitle.Success)
                        {
                            string threadTitleHtml = mThreadTitle.Value.Trim();
                            threadTitle = RegexUtility.ExtractHtmlContent("a", threadTitleHtml);
                            string href = RegexUtility.ExtractHyperlink(threadTitleHtml);
                            threadLinkDetail = Utility.RemoveQueryStringByKey(new Uri(newUri, href).ToString(), "s");
                        }
                        //Extract User name info
                        Regex regexUserCreatedThread = new Regex("<a [^>]* class=\"username .*?\">.*?</a>");
                        Match mUserCreatedThread = regexUserCreatedThread.Match(threadContent);
                        if (mUserCreatedThread.Success)
                        {
                            string userNameInfo = mUserCreatedThread.Value.Trim();
                            userName = RegexUtility.ExtractHtmlContent("a", userNameInfo);
                            string href = RegexUtility.ExtractHyperlink(userNameInfo);
                            userLinkDetail = Utility.RemoveQueryStringByKey(new Uri(newUri, href).ToString(), "s");
                            Regex regexDateTime = new Regex(@"(?<=\btitle="")[^""]*");
                            Match mDateTime = regexDateTime.Match(userNameInfo);
                            string dateTimeTemp = mDateTime.Value.Trim();
                            /*Regex regexDateTimeValue = new Regex(@"(?<day>\d{2})\/(?<month>\d{2})\/(?<year>\d{4})(?:[\D]*)(?<time>\d{1,2}\:\d{2}\s(?:A|P)M)");
                            Match mDateTimeValue = regexDateTimeValue.Match(userNameInfo);
                            if (mDateTimeValue.Success)
                            {
                                DateTime dateTime = DateTime.Parse(String.Format("{0}/{1}/{2} {3}",
                                    mDateTimeValue.Groups["month"].Value,
                                    mDateTimeValue.Groups["day"].Value,
                                    mDateTimeValue.Groups["year"].Value,
                                    mDateTimeValue.Groups["time"].Value));
                            }*/
                            //dateTime = Regex.Replace(dateTimeTemp, @"[^\d]", string.Empty);//extract number from string
                            dateTime = dateTimeTemp.Replace(Regex.Replace(dateTimeTemp, @"\d{2}-\d{2}-\d{4} \d{2}:\d{2}", string.Empty).ToString(), string.Empty);
                            if (!string.IsNullOrEmpty(dateTime))
                            {
                                postDate = Utility.ConvertToDateTimeObject(dateTime, item.DateTimeFormat);
                            }
                        }
                        //Extract content of topic
                        Regex regexContentTopic = new Regex("<p class=\"threaddesc\">.*?</p>");
                        Match mContentTopic = regexContentTopic.Match(threadContent);
                        if (mContentTopic.Success)
                        {
                            string postContentHtml = mContentTopic.Value.Trim();
                            postContent = RegexUtility.ExtractTextFromHtmlTag(postContentHtml);
                        }
                        //Extract comments of this topic
                        List<Comment> comments = new List<Comment>();
                        Utility.ExtractComments(threadLinkDetail, item, ref comments);

                        //Add Announcement to detected announcement
                        if (!string.IsNullOrEmpty(threadTitle) && !string.IsNullOrEmpty(postContent))
                        {
                            Announcement ann = new Announcement();
                            ann.Title = threadTitle;
                            ann.DateTime = postDate;
                            ann.DateNumberic = long.Parse(
                                            postDate.ToString("yyyyMMddHHmmss"));
                            ann.SocialNetwork.ScreenName = userName;
                            ann.Message = postContent;
                            ann.SocialNetwork.Comments = comments;
                            ann.SocialNetwork.AccountLink = userLinkDetail;
                            ann.Attachment = false;
                            ann.InsertedDate = DateTime.Now;
                            ann.LangId = item.LangId;
                            ann.SourceId = item.SourceId;
                            ann.SourceCode = item.SourceCode;                            
                            detectedAnnouncements.Add(ann);
                        }
                    }
                    //Extract url for next page
                    Regex regNextPage = new Regex("<span class=\"selected\">.*?</span>(?<span>.*?</span>)");
                    Match mNextPage = regNextPage.Match(remainHtml);
                    if (mNextPage.Success)
                    {
                        string nextPageHtml = mNextPage.Value;
                        string link = RegexUtility.ExtractHyperlink(nextPageHtml);
                        if (!string.IsNullOrEmpty(link))
                            item.Url = Utility.RemoveQueryStringByKey(new Uri(newUri, link).ToString(), "s");
                    }
                }

                // check if has next page 
                // next page counts as a new request, so it needed insert into request queue
                if (Utility.CheckNextPage(html))
                {
                    SourceItem nItem = new SourceItem(item.Url, item.LangId, item.SourceCode, item.SearchCode, item.SourceId, item.DateTimeFormat);
                    if (!string.IsNullOrEmpty(item.RequestBuilderType))
                        nItem.RequestBuilderType = item.RequestBuilderType;

                    if (!string.IsNullOrEmpty(item.HtmlParserType))
                        nItem.HtmlParserType = item.HtmlParserType;

                    nItem.PrevResponseHtml = html;
                    attachNewItemSource(nItem);
                }


                // insert into download queue when no error in parsing
                foreach (Announcement ann in detectedAnnouncements)
                {
                    attachResultItem(ann);
                }

                // if this request is fail request in previous scanning, 
                // remove it when success in current scanning
                if (item.FailId > 0)
                    Utility.DeleteFailRequests(item.FailId);
            }
            catch (Exception ex)
            {
                // if has an error, save fail request to next time scanning
                if (item.FailId == 0)
                {
                    item.FailId = DateTime.Now.Ticks;
                    Utility.SaveFailRequests(item);
                }

                // then write log
                string message = string.Format(@"
            Company code:   {0}
            HTML Parsing:   Fail
            Request URL:    {1}
            Search key:     {2}", item.SourceCode, item.Url, item.SearchCode);
                Logger.WriteError(message, ex);
            }
        }

        public void Parse(List<SourceItem> items, string html, Action<Model.Partials.Announcement> attachResultItem)
        {
            throw new NotImplementedException();
        }
    }

    public class OtofunParserUpdate : OtofunParser
    {
        private string searchCode;
        private int? languageId;
        private DateTime? dateFrom;
        private DateTime? dateTo;

        /// <summary>
        /// Create a new instance by providing the particular parameters
        /// </summary>
        /// <param name="searchCode">Company code to find pressreleases</param>
        /// <param name="languageId">
        ///     Language Id to find relatively pressreleases. The value can accept NULL value.
        ///     When value is NULL, it means that for every languages
        /// </param>
        /// <param name="dateFrom">The date to start scanning from</param>
        /// <param name="dateTo">The date to start canning to</param>
        public OtofunParserUpdate(string searchCode, int? languageId, DateTime? dateFrom, DateTime? dateTo)
        {
            this.searchCode = searchCode;
            this.languageId = languageId;
            this.dateFrom = dateFrom;
            this.dateTo = dateTo;
        }

        public void Parse(SourceItem item, string html, Action<Model.Partials.Announcement> attachResultItem, Action<SourceItem> attachNewItemSource)
        {
            throw new NotImplementedException();
        }
    }
}
